<template>
  <div class="list-units">
    <div class="units-nav">
      <Steps v-model="units" :statusKey="'stepStatus'">
        <template v-slot:head="item">
          <div class="item-head">
            <div class="unit-name">{{ item.scope.name }}</div>
            <span v-if="!isView" class="unit-action">
              <div class="d-dropdown d-drop-hover d-drop-right">
                <MenuIcon title="更多" />
                <div class="d-list-menu d-list-cascade d-list-cascade-right">
                  <ul class="d-list-menu-group">
                    <!-- <li class="d-list-menu-item d-list-menu-item-setting">
                      <a @click="handleRunItem(item, i)" class="d-list-item-row">
                        <ExecuteRoundIcon class="d-list-item-icon" title="执行" />
                        <span class="d-list-item-text">执行</span>
                      </a>
                    </li> -->
                    <li class="d-list-menu-item d-list-menu-item-setting">
                      <a @click="handleEditNode(item.scope)" class="d-list-item-row">
                        <EditIcon class="d-list-item-icon" title="编辑" />
                        <span class="d-list-item-text">编辑</span>
                      </a>
                    </li>
                    <li v-if="!isView" class="d-list-menu-item d-list-menu-item-del">
                      <a @click="handleDelNode(item.scope)" class="d-list-item-row">
                        <DeleteIcon class="d-list-item-icon" title="删除" />
                        <span class="d-list-item-text">删除</span>
                      </a>
                    </li>
                  </ul>
                </div>
              </div>
            </span>
          </div>
        </template>
        <template v-slot:head-content="item">
          <div :class="'item-' + item.scope.id" class="item-content">
            <Collapse v-if="item.scope.isCollapse">
              <CollapseItem :caption="'打开或关闭'">
                <div class="executor-view"></div>
              </CollapseItem>
            </Collapse>
            <div v-else class="executor-view"></div>
          </div>
        </template>
      </Steps>
    </div>
  </div>
</template>

<script>
import { PanerForm } from '@daelui/vdog/dist/pages'
import { Dialoger, FormCalendar, FormSelecter, Collapse, CollapseItem } from '@daelui/vdog/dist/components'
import { EditIcon, DeleteIcon, MenuIcon } from '@daelui/vdog/dist/icons'
import unitSer from '../../../service/action/exeunit.action'
import { parser, coder } from '@daelui/dogjs/dist/components'
import storeMan from '../../../components/store-man'
import Steps from './steps.vue'
import Vue from 'vue'
import { state } from '../../../service/stock/index.js'

export default {
  components: {
    PanerForm,
    FormSelecter,
    FormCalendar,
    Dialoger,
    MenuIcon,
    EditIcon,
    DeleteIcon,
    Steps,
    Collapse,
    CollapseItem
  },

  props: {
    // 流程对象
    execute: {
      type: Object,
      default () {
        return {}
      }
    },
    // 模式
    mode: {
      type: String,
      default () {
        return ''
      }
    }
  },

  data () {
    return {
      // 源单元列表
      unitList: [],
      units: [],
      // 执行类型
      runTypeList: state.runTypeList,
      // 视图列表
      visualList: state.visualList,
      // 缓存数据
      cacheData: {}
    }
  },

  computed: {
    isView () {
      return this.mode === 'view'
    }
  },

  watch: {
    'execute.id' () {
      this.reload()
    }
  },

  methods: {
    /**
     * @function 编辑节点
    */
    handleEditNode (node) {
      this.$emit('editNode', node)
    },
    /**
     * @function 删除节点
    */
    handleDelNode (node) {
      this.$emit('delNode', node)
    },

    /**
     * @function 加载数据
    */
    reload () {
      let execute = this.execute || {}
      execute.data = parser.parse(execute.data, 'object', true)
      let units = execute.data.units
      units = Array.isArray(units) ? units : []
      // 解析单元配置
      this.solveUnits(units)
      this.units = units
      this.execute.data.units = units
      this.initViewRender()
    },

    /**
     * @function 解析单元配置
    */
    solveUnits (units) {
      units = units || this.units
      units.forEach(item => {
        let unit = this.getUnit(item.uid) || {}
        item.name = item.name || unit.name
        item.executor = item.executor || unit.executor
        if (item.isExecutorOrigin === true) {
          item.executor = unit.executor || item.executor
        }
        item.input = item.input || unit.input
        if (item.isInputOrigin === true) {
          item.input = unit.input || item.input
        }
        item.output = item.output || unit.output
        if (item.isOutputOrigin === true) {
          item.output = unit.output || item.output
        }
        item.isHide = this.isView && item.isHidden
        item.status = item.status || unit.status || ''
        item.type = unit.type || item.type || ''
        item.runType = unit.runType || item.runType || ''
        item.cid = unit.cid || item.cid || ''
      })
      return units
    },

    /**
     * @function 获取单元
    */
    getUnit (id) {
      return this.unitList.find(item => String(item.id) === String(id))
    },
    /**
     * @function 获取组件
    */
    getComponent (id) {
      return this.visualList.find(item => String(item.id) === String(id))
    },
    /**
     * @function 初始化预览渲染
    */
    initViewRender () {
      // 缓存
      storeMan.getItem('executor-cycle-' + this.execute.id).then(cacheConfig => {
        cacheConfig = parser.parse(cacheConfig, 'object', true, {})
        this.cacheData = cacheConfig
        let config = Object.assign({}, (this.execute.data || {}).config || {}, this.cacheData || {})
        let isCycle = false
        if (String(config.isCycle) === '1' || String(config.isCycle) === 'true') {
          isCycle = true
          this.stopTimer()
          this.runCycle()
        }
        this.$emit('onInitRender', this, isCycle)
      })
    },
    /**
     * @function 重置
    */
    handleReset () {
      this.units.forEach(item => {
        this.$set(item, 'stepStatus', '')
      })
    },

    /**
     * @function 执行
    */
    handleRun () {
      // 初始
      let defer = Promise.resolve({
        data: {},
        index: -1,
        units: this.units,
        parent: this
      })
      this.units.forEach(item => {
        this.$set(item, 'stepStatus', '')
      })
      let results = []
      // 遍历节点
      for (let i = 0; i < this.units.length; i++) {
        let item = this.units[i]
        let payload = {
          index: i,
          units: this.units,
          parent: this,
          results: results
        }
        try {
          // 组件类型
          let runType = item.runType
          let typeItem = this.runTypeList.find(item => String(item.id) === String(runType)) || {}
          // 是否组件
          let isComp = typeItem.key === this.runTypeList.COMPONENT
          if (!item.executorModule || !item.inputModule || item.outputModule) {
            let defCode = `export default function (payload) { return payload }`
            let defExp = { default (a) { return a } }
            let executor = item.executor || defCode
            let input = item.input || defCode
            let output = item.output || defCode
            try {
              executor = coder.compile(executor, window.Babel, window.preset)
            } catch (e) {
              executor = defExp
              console.log(e)
              break
            }
            try {
              input = coder.compile(input, window.Babel, window.preset)
            } catch (e) {
              input = defExp
              console.log(e)
              break
            }
            try {
              output = coder.compile(output, window.Babel, window.preset)
            } catch (e) {
              output = defExp
              console.log(e)
              break
            }
            item.executorModule = executor
            item.inputModule = input
            item.outputModule = output
          }
          // 输入执行与过程执行
          defer = defer.then(res => {
            res = res || {}
            payload.data = res.data || {}
            payload.prevPayload = res
            results.push(res)
            return item.inputModule.default(payload)
          }).then(res => {
            return item.executorModule.default(res)
          }).catch(e => {
            console.log(e)
            return e
          })
          // 组件执行
          if (isComp) {
            let comp = this.getComponent(item.cid)
            if (comp) {
              let isBuild = true
              let view = item.execComponent
              if (!view) {
                view = new Vue(Vue.extend(comp.component))
                let containerEl = this.$el.querySelector('.item-' + item.id)
                view.$mount(containerEl.querySelector('.executor-view'))
                item.execComponent = view
                isBuild = false
              }
              defer = defer.then(res => {
                if (isBuild && view.update) {
                  return view.update(res)
                } else if (view.run) {
                  return view.run(res)
                } else {
                  view.config = res?.config
                  view.data = res?.data
                  return res
                }
              }).catch((e) => {
                console.log(e)
              })
            }
          }
          // 结果执行
          defer = defer.then(res => {
            let result = item.outputModule.default(res)
            this.$set(item, 'stepStatus', 'success')
            return result
          }).catch(() => {})
        } catch (e) {
          this.$set(item, 'stepStatus', 'error')
          defer.catch(new Error('解析错误'))
          break
        }
      }
      if (this.isCycle()) {
        this.runTimeout()
      }
      return defer
    },

    /**
     * @function 执行周期
    */
    runTimeout () {
      clearTimeout(this.timer)
      // 周期时间秒数
      let config = Object.assign({}, (this.execute.data || {}).config || {}, this.cacheData || {})
      let time = config.cycleTime
      time = parseInt(time)
      time = isNaN(time) ? 5 * 60 * 1000 : time * 1000
      this.timer = setTimeout(() => {
        this.handleRun()
      }, time)
    },

    /**
     * @function 执行周期执行
    */
    handleCycle () {
      let config = (this.execute.data || {}).config || {}
      this.cacheData = Object.assign(this.cacheData, config)
      config = Object.assign({}, config, this.cacheData || {})
      storeMan.setItem('executor-cycle-' + this.execute.id, parser.stringify(this.cacheData), {cache: true})
      let isCycle = false
      if (config.isCycle) {
        isCycle = true
        this.runCycle()
      } else {
        this.stopCycle()
      }
      return Promise.resolve(isCycle)
    },

    isCycle () {
      let config = (this.execute.data || {}).config || {}
      let isCycle = config.isCycle
      return String(isCycle) === '1' || String(isCycle) === 'true'
    },

    /**
     * @function 切换周期执行
    */
    switchCycle (val) {
      if (val) {
        this.runCycle()
      } else {
        this.stopCycle()
      }
    },

    /**
     * @function 周期执行
    */
    runCycle () {
      this.stopTimer()
      this.runTimeout()
    },

    /**
     * @function 停止周期执行
    */
    stopCycle () {
      this.stopTimer()
    },

    /**
     * @function 停止执行
    */
    stopTimer () {
      clearTimeout(this.timer)
    }
  },

  beforeMount () {
    // 查询单元列表
    unitSer.queryListPage({size: 1000}).then(res => {
      this.unitList = res.data.list
    }).then(() => {
      this.reload()
    })
  },

  mounted () {

  },

  beforeDestroy () {
    this.stopTimer()
  }
}
</script>

<style lang="less" scoped>
.list-units {
  .units-nav {
    padding: 12px;
    background: #fff;
  }
  .item-head {
    display: flex;
    margin-bottom: 12px;
    .unit-name {
      flex: 1;
    }
    .unit-action {
      color: #333;
      padding-left: 12px;
      .d-list-item-text {
        font-size: 14px;
        font-weight: 400;
      }
    }
    .item-content {
      clear: both;
    }
  }
}
</style>
